<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Elliptical Drag with GSAP and SVG</title>
    <style>
        svg {
            display: block;
            margin: 50px auto;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
</head>

<body>
    <svg width="400" height="200" viewBox="0 0 200 100">
        <ellipse cx="100" cy="50" rx="80" ry="40" stroke="black" stroke-width="1" fill="none" />
        <circle cx="100" cy="10" r="5" fill="red" id="draggableNode" cursor="pointer" />
    </svg>

    <script>
        const draggableNode = document.getElementById('draggableNode');
        const svg = document.querySelector('svg');
        const ellipseCX = 100; // 椭圆的中心X坐标
        const ellipseCY = 50; // 椭圆的中心Y坐标
        const ellipseRX = 80; // 椭圆的长轴半径
        const ellipseRY = 40; // 椭圆的短轴半径

        let offsetX, offsetY, dragging = false;

        draggableNode.addEventListener('mousedown', (e) => {
            const pt = svg.createSVGPoint();
            pt.x = e.clientX;
            pt.y = e.clientY;
            const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse());

            offsetX = cursorPt.x - draggableNode.cx.baseVal.value;
            offsetY = cursorPt.y - draggableNode.cy.baseVal.value;

            dragging = true;
            document.addEventListener('mousemove', onMouseMove);
            document.addEventListener('mouseup', onMouseUp);
        });

        function onMouseMove(e) {
            if (!dragging) return;

            const pt = svg.createSVGPoint();
            pt.x = e.clientX;
            pt.y = e.clientY;
            const cursorPt = pt.matrixTransform(svg.getScreenCTM().inverse());

            let newX = cursorPt.x - offsetX;
            let newY = cursorPt.y - offsetY;

            // 限制节点在椭圆路径上移动
            const angle = Math.atan2(newY - ellipseCY, newX - ellipseCX);
            const radiusX = ellipseRX;
            const radiusY = ellipseRY;

            newX = ellipseCX + radiusX * Math.cos(angle);
            newY = ellipseCY + radiusY * Math.sin(angle);

            gsap.to(draggableNode, {
                duration: 0.1,
                attr: {
                    cx: newX,
                    cy: newY
                }
            });
        }

        function onMouseUp() {
            dragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
        }
    </script>
</body>

</html>